package cn.com.xjnt.vas.manage.service.impl;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.frameworks.core.shiro.ShiroDbService;
import com.frameworks.core.shiro.ShiroUser;
import com.google.common.collect.Lists;

import cn.com.xjnt.vas.manage.domain.entity.Account;
import cn.com.xjnt.vas.manage.domain.entity.AccountRole;
import cn.com.xjnt.vas.manage.domain.entity.OrganizationRole;
import cn.com.xjnt.vas.manage.domain.entity.Permission;
import cn.com.xjnt.vas.manage.domain.entity.Role;
import cn.com.xjnt.vas.manage.domain.entity.RolePermission;
import cn.com.xjnt.vas.manage.repository.AccountRepository;
import cn.com.xjnt.vas.manage.repository.AccountRoleRepository;
import cn.com.xjnt.vas.manage.repository.OrganizationRoleRepository;
import cn.com.xjnt.vas.manage.repository.RoleRepository;

@Service
@Transactional
public class ShiroDbServiceImpl implements ShiroDbService {

	private static final Logger logger = LogManager.getLogger(ShiroDbServiceImpl.class);
	
	@Autowired
	private AccountRepository accountRepository;
	
	@Autowired
	private AccountRoleRepository accountRoleRepository;
	
	@Autowired
	private OrganizationRoleRepository organizationRoleRepository;
	
	@Autowired
	private RoleRepository roleRepository;
	
	@Override
	public ShiroUser findById(Long id) {
		Account account = accountRepository.findOne(id);
		ShiroUser user = new ShiroUser(account.getId(), account.getUsername());
		user.setAccount(account);
		return user;
	}

	@Override
	public ShiroUser findByUsername(String username) {
		Account account = accountRepository.findByUsername(username);
		ShiroUser user = new ShiroUser(account.getId(), account.getUsername());
		user.setAccount(account);
		return user;
	}

	@Override
	public List<Role> findAll() {
		return roleRepository.findAll();
	}

	@Override
	public Collection<Role> findByShiroUser(ShiroUser shiroUser) {
		List<AccountRole> accountRoles = accountRoleRepository.findByAccountId(shiroUser.getId());
		List<OrganizationRole> organizationRoles = organizationRoleRepository.findByOrganizationId(shiroUser.getAccount().getOrganization().getId());
		return getUserRoles(accountRoles, organizationRoles);
	}
	
	/**
	 * 组装角色权限
	 * @param roles
	 * @param shiroUser
	 * @return
	 */
	public Collection<String> makeRoles(Collection<Role> roles, ShiroUser shiroUser) {
		Collection<String> hasRoles = new HashSet<String>();
		for (Role role : roles) {
			hasRoles.add(role.getCode());
		}
		
		if (logger.isInfoEnabled()) {
			logger.info(shiroUser.getLoginName() + "拥有的角色:" + hasRoles);
		}
		return hasRoles;
	}
	
	/**
	 * 组装资源操作权限
	 * @param roles
	 * @param shiroUser
	 * @return
	 */
	public Collection<String> makePermissions(Collection<Role> roles, ShiroUser shiroUser) {
		
		Collection<String> stringPermissions = Lists.newArrayList();
		for (Role role : roles) {
			List<RolePermission> rolePermissions = role.getRolePermissions();
			for (RolePermission rolePermission : rolePermissions) {
				Permission permission = rolePermission.getPermission();
				
				String resource = permission.getModule().getCode();
				String operate = permission.getCode();
		
				StringBuilder builder = new StringBuilder();
				builder.append(resource + ":" + operate);
								
				stringPermissions.add(builder.toString());
			}
		}

		if (logger.isInfoEnabled()) {
			logger.info(shiroUser.getLoginName() + "拥有的权限:" + stringPermissions);
		}
		return stringPermissions;
	}

	private Collection<Role> getUserRoles(List<AccountRole> accountRoles, List<OrganizationRole> organizationRoles) {
		Set<Role> roles = new HashSet<Role>();
		for (AccountRole accountRole : accountRoles) {
			roles.add(accountRole.getRole());
		}

		for (OrganizationRole organizationRole : organizationRoles) {
			roles.add(organizationRole.getRole());
		}
		return roles;
	}

}
